﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace IDCardValidator.Core
{
    public static class Tools
    {
        /// <summary>
        /// 中国内地身份证号检验
        /// </summary>
        /// <param name="idcard">15位或者18倍身份证号</param>
        /// <returns></returns>
        public static bool IsIDCard(string idcard)
        {
            if (string.IsNullOrWhiteSpace(idcard.Trim()))//为空假
            {
                return false;
            }
            idcard = GetBanJiao(idcard.ToUpper());
            int len = idcard.Length;
            if (len != 15 && len != 18)//位数不足假
            {
                return false;
            }
            else if (len == 15)
            {
                //检查输入是否为数字
                if (!Regex.IsMatch(idcard, @"^\d*$"))
                {
                    return false;
                }
                //出生日期
                string birthday = "19" + idcard.Substring(6, 6);
                string year = birthday.Substring(0, 4);
                string month = birthday.Substring(4, 2);
                string day = birthday.Substring(6, 2);
                birthday = string.Format("{0}-{1}-{2}", year, month, day);

                DateTime date = new DateTime();
                if (!DateTime.TryParse(birthday, out date))//生日不对
                {
                    return false;
                }
                return true;
            }
            else if (len == 18)
            {
                //17位加权因子
                int[] wi = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
                string id17 = idcard.Substring(0, 17);//获取身份证的前17位
                string idend = idcard.Substring(17); //获取身份证的效验位（第18位）
                int sum = 0;
                //加权求和id[i]*wi[i]求和
                for (int i = 0; i < id17.Length; i++)
                {
                    sum += Convert.ToInt32(id17[i].ToString()) * wi[i];
                }
                //效验码
                string[] xiaoyanma = { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" };
                //  用加权求和的值与11进行求余运算，并与效验码对应位数进行比较
                if (idend == xiaoyanma[sum % 11])
                {
                    return true; //成功返回true
                }
                else
                {
                    return false; //失败返回false
                }
            }
            return false;
        }
        /// <summary>
        /// 中国香港身份证
        /// </summary>
        /// <param name="idcard"></param>
        /// <returns></returns>
        public static bool IsHKIDCard(string idcard)
        {
            if (string.IsNullOrWhiteSpace(idcard.Trim()))//为空假
            {
                return false;
            }
            idcard = GetBanJiao(idcard.ToUpper());
            idcard = idcard.Replace("(", "").Replace(")", "");//G123456(A) 转换成 G123456A
            int len = idcard.Length;
            if (len != 8 && len != 9)//香港身份证目前长度有2种，8位和9位
            {
                return false;
            }
            if (len == 8)//补一位空格
            {
                idcard = "_" + idcard;
            }
            //检查输入是否为数字
            if (!Regex.IsMatch(idcard.Substring(2, 6), @"^\d*$"))
            {
                return false;
            }
            //https://zh.wikipedia.org/wiki/%E9%A6%99%E6%B8%AF%E8%BA%AB%E4%BB%BD%E8%AD%89#身份證號碼
            int[] xishu = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
            #region MyRegion
            Dictionary<string, int> dict = new Dictionary<string, int>();
            dict.Add("A", 10);
            dict.Add("B", 11);
            dict.Add("C", 12);
            dict.Add("D", 13);
            dict.Add("E", 14);
            dict.Add("F", 15);
            dict.Add("G", 16);
            dict.Add("H", 17);
            dict.Add("I", 18);
            dict.Add("J", 19);
            dict.Add("K", 20);
            dict.Add("L", 21);
            dict.Add("M", 22);
            dict.Add("N", 23);
            dict.Add("O", 24);
            dict.Add("P", 25);
            dict.Add("Q", 26);
            dict.Add("R", 27);
            dict.Add("S", 28);
            dict.Add("T", 29);
            dict.Add("U", 30);
            dict.Add("V", 31);
            dict.Add("W", 32);
            dict.Add("X", 33);
            dict.Add("Y", 34);
            dict.Add("Z", 35);
            dict.Add("_", 36);//3 
            #endregion
            int sum = 0;
            for (int i = 0; i < 9; i++)
            {
                string wei = idcard.Substring(i, 1);
                int haoma = 0;
                if (!Regex.IsMatch(wei, @"^\d*$"))//是字母
                {
                    haoma = dict[wei] % 11;//取余
                    if (dict[wei] == 36)//空格36转为3
                    {
                        haoma = 3;
                    }
                    if (dict[wei] == 10)//A不用算余数
                    {
                        haoma = 10;
                    }
                }
                else//是数字,中间6位或者带最后1位
                {
                    haoma = Convert.ToInt32(wei);
                }
                int chengji = haoma * xishu[i] > 10 ? haoma * xishu[i] % 11 : haoma * xishu[i];
                sum += chengji;
            }
            if (sum % 11 != 0)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 中国台湾身份证
        /// </summary>
        /// <param name="idcard">目前的中國台灣身份證字号一共有十码，包括起首一个大写的英文字母与接续的九个阿拉伯数字。</param>
        /// <returns></returns>
        public static bool IsTWIDCard(string idcard)
        {
            if (string.IsNullOrWhiteSpace(idcard.Trim()))//为空假
            {
                return false;
            }
            idcard = GetBanJiao(idcard.ToUpper());
            int len = idcard.Length;
            if (len != 10)
            {
                return false;
            }
            //中國台灣身份證校验码系数数组
            int[] xishu = { 1, 9, 8, 7, 6, 5, 4, 3, 2, 1,1};
            //判断首个字母是否有效，其余部分是否为数字
            string addressCode = idcard.Substring(0, 1);
            string orderCode = idcard.Substring(1, 9);
            #region 中國台灣身份證区域码映射表
            Dictionary<string, int> dict = new Dictionary<string, int>();
            dict.Add("A", 10);//台北市
            dict.Add("B", 11);//台中市
            dict.Add("C", 12);//基隆市
            dict.Add("D", 13);//台南市
            dict.Add("E", 14);//高雄市
            dict.Add("F", 15);//新北市
            dict.Add("G", 16);//宜兰县
            dict.Add("H ", 17);//桃园市
            dict.Add("I", 34);//嘉义市
            dict.Add("J", 18);//新竹县
            dict.Add("K", 19);//苗栗县
            dict.Add("M", 21);//南投县
            dict.Add("N", 22);//彰化县
            dict.Add("O", 35);//新竹市
            dict.Add("P", 23);//云林县
            dict.Add("Q", 24);//嘉义县
            dict.Add("T", 27);//屏东县
            dict.Add("U", 28);//花莲县
            dict.Add("V", 29);//台东县
            dict.Add("W", 32);//金门县
            dict.Add("X", 30);//澎湖县
            dict.Add("Z", 33);//连江县
            dict.Add("L", 20);//台中县
            dict.Add("R", 25);//台南县
            dict.Add("S", 26);//高雄县
            dict.Add("Y", 31);//阳明山管理局 
            #endregion
            if(!dict.ContainsKey(addressCode))
            {
                return false;
            }
            //检查输入是否为数字
            if (!Regex.IsMatch(orderCode, @"^\d*$"))
            {
                return false;
            }
            //校验身份证有效性
            string tmp = dict[addressCode].ToString();
            //合成一个新数
            orderCode = tmp + orderCode;
            //计算每一位积之和
            int sum = 0;
            for (int i = 0; i < 11; i++)
            {
                sum += Convert.ToInt32(orderCode.Substring(i, 1)) * xishu[i];
            }
            if (sum % 10 != 0)
            {
                return false;
            }
            //身分证号“A123456789”因可符合验证规则，故常遭冒用。
	        //持该身分证号者为出生于台北市内湖区的新北市民谢条根，他经常出入法院只为解决冒用所引发的纠纷，虽可透过更换身分证号避免，但因换号后连带要更换许多文件，该人尚无意愿换号。
            //所有校验通过
            //if(idcard== "A123456789")
            //{
            //    return false;
            //}
            return true;
        }
        /// <summary>
        /// 中国澳门身份证
        /// </summary>
        /// <param name="idcard"></param>
        /// <returns></returns>
        public static bool IsMOIDCard(string idcard)
        {
            if (string.IsNullOrWhiteSpace(idcard.Trim()))//为空假
            {
                return false;
            }
            idcard = GetBanJiao(idcard.ToUpper());
            idcard = idcard.Replace("(", "").Replace(")", "").Replace("/", "");//XNNNNNN(Y)
            int len = idcard.Length;
            if (len != 8)
            {
                return false;
            }
            //检查输入是否为数字
            if (!Regex.IsMatch(idcard, @"^\d*$"))
            {
                return false;
            }
            int firstCode = Convert.ToInt32(idcard.Substring(0, 1));
            if (firstCode != 1 && firstCode != 5 && firstCode != 7)//判断是否为1、5、7开头
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 全角转半角
        /// </summary>
        /// <param name="QJstr"></param>
        /// <returns></returns>
        static string GetBanJiao(string QJstr)
        {
            char[] c = QJstr.ToCharArray();
            for (int i = 0; i < c.Length; i++)
            {
                byte[] b = System.Text.Encoding.Unicode.GetBytes(c, i, 1);
                if (b.Length == 2)
                {
                    if (b[1] == 255)
                    {
                        b[0] = (byte)(b[0] + 32);
                        b[1] = 0;
                        c[i] = System.Text.Encoding.Unicode.GetChars(b)[0];
                    }
                }
            }
            string strNew = new string(c);
            return strNew;
        }
        
    }    
}
